#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>

#include "pointoperation.h"
#include "utils.h"
#include <gmp.h>

#include "kdf.h"
#include "sm2.h"
#include "sm3.h"

void test_sm2();

int main()
{

	test_sm2();
}

void test_sm2()
{
	// 参数初始化
	param sm2_param;
	sm2_param_init(sm2_param);

	// 坐标的长度
	size_t position_len = 32;

	// 1.密钥生成
	println("1.密钥生成");

	// 进制基数
	int base = 16;
	// 私钥
	mpz_t private_key;
	mpz_init(private_key);
	// 128B2FA8 BD433C6C 068C8D80 3DFF7979 2A519A55 171B1B65 0C23661D 15897263
	mpz_set_str(private_key, "128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263", base);
	gmp_printf("private_key = %ZX\n", private_key);

	// 基点G、公钥
	point base_point, public_key;
	point_inits(base_point, public_key, NULL);

	// 421DEBD6 1B62EAB6 746434EB C3CC315E 32220B3B ADD50BDC 4C4E6C14 7FEDD43D
	mpz_set_str(base_point->x, "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", base);

	// 0680512B CBB42C07 D47349D2 153B70C4 E5D7FDFC BFA36EA1 A85841B9 E46E09A2
	mpz_set_str(base_point->y, "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", base);

	// 根据私钥生成公钥
	public_key_gen(public_key, private_key, sm2_param, base_point);

	gmp_printf("public_key->x = %ZX\n", public_key->x);
	gmp_printf("public_key->y = %ZX\n", public_key->y);

	// 2.SM2签名
	println("2.SM2签名");

	// 2.1.拼接基本信息
	uint8_t id[19] = "ALICE123@YAHOO.COM";
	// id长度，单位字节
	size_t id_len = strlen(id);
	print_chars_by_hex("id", id, id_len);

	// ent_len = id_len * 8。转换为字节的时候，占2个字节
	size_t ent_len = id_len * 8;

	// base_info = ent_len || id || a || b || xG || yG || xA || yA
	size_t base_info_len = 2 + id_len + position_len * 6;
	uint8_t *base_info = malloc(sizeof(uint8_t) * base_info_len);
	concat_base_info(base_info, base_info_len, ent_len, id, id_len, sm2_param, base_point, public_key);
	print_chars_by_hex("基本信息拼接的结果", base_info, base_info_len);

	// 2.2.哈希基本信息 得到Z_A
	size_t hash_str_len = 32;
	uint8_t hash_str[hash_str_len];
	hash(hash_str, base_info, base_info_len);
	print_chars_by_hex("基本信息哈希的结果", hash_str, hash_str_len);

	// 2.3.生成签名
	uint8_t msg[] = "message digest";
	// 去除"\0"
	uint8_t msg_len = strlen(msg);
	size_t sign_len = 2 * position_len + 1;
	uint8_t *sign = malloc(sizeof(uint8_t) * sign_len);
	// 注意只有一个字符 \0 只用于打印字符串，不在其他地方使用
	sign[sign_len] = '\0';

	printf("明文：%s\n", msg);
	sm2_sign(sign, sign_len, sm2_param, base_point, private_key, hash_str, hash_str_len, msg, msg_len);

	print_chars_by_hex("SM2签名结果", sign, sign_len - 1);

	// 3.SM2验证签名
	println("3.SM2验证签名");
	char temp = sign[0];
	int ret = sm2_verify_sign(sm2_param, base_point, public_key, hash_str, hash_str_len, msg, msg_len, sign, sign_len - sign_len);
	if (ret == 1)
	{
		printf("SM2验签成功\n");
	}
	else
	{
		printf("SM2验签失败\n");
	}

	// 修改测试
	sign[0] = 0x11;
	ret = sm2_verify_sign(sm2_param, base_point, public_key, hash_str, hash_str_len, msg, msg_len, sign, sign_len - sign_len);

	if (ret == 1)
	{
		printf("SM2验签成功\n");
	}
	else
	{
		printf("SM2验签失败\n");
	}

	// 还原测试
	sign[0] = temp;
	ret = sm2_verify_sign(sm2_param, base_point, public_key, hash_str, hash_str_len, msg, msg_len, sign, sign_len - sign_len);
	if (ret == 1)
	{
		printf("SM2验签成功\n");
	}
	else
	{
		printf("SM2验签失败\n");
	}

	// 4.收尾操作
	free(base_info);
	free(sign);
}